import {
    addIcon, App,
    MarkdownView,
    Plugin, PluginSettingTab, Setting, Editor, Notice
} from "obsidian";
import getShortcutByName from "./slash/api/getShortcutByName";
import updateHighlightComments from "./slash/api/updateHighlightComments";
import fetchHighlightComments from "./slash/api/fetchHighlightComments";
import fetchHighlights from "./slash/api/fetchHighlights";
// import * as https from "https";

interface PluginSettings {
    newLinkText: string,
    highlightBullet: string,
    toggleRegenerateFromDetail: boolean,
}

const DEFAULT_SETTINGS: PluginSettings = {
    newLinkText: "在网页显示高亮",
    highlightBullet: "▲",
    toggleRegenerateFromDetail: false,
}
const URL_HASH_PREFIX = '#~:~highlights=';
const urlHashPrefixRegex = new RegExp(`${URL_HASH_PREFIX}(.*?)(#|$)`)

//Add chevron-up-square icon from lucide for mobile toolbar (temporary until Obsidian updates to Lucide v0.130.0)
addIcon("chevron-up-square", `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevron-up-square"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"></rect><polyline points="8,14 12,10 16,14"></polyline></svg>`);

export default class WebHighlighterLinkPlugin extends Plugin {
    settings: PluginSettings

    async onload() {
        await this.loadSettings();

        this.addCommand({
            id: "push-to-web-highlighter",
            name: "push to slash by selection",
            icon: "plus-square",
            callback: () => {
                this.updateHighlightToSlash();
            },
        });
        this.addCommand({
            id: "pull-from-web-highlighter",
            name: "pull from slash by selection",
            icon: "plus-square",
            callback: () => {
                this.pullHighlightFromSlash();
            },
        });
        this.registerEvent(
          this.app.workspace.on("editor-menu", (menu, editor, view) => {
              menu.addItem((item) => {
                  item
                    .setTitle("push highlight to slash")
                    .setIcon("plus-square")
                    .onClick(async () => {
                        await this.updateHighlightToSlash();
                    });
              });
              menu.addItem((item) => {
                  item
                    .setTitle("pull highlight from slash")
                    .setIcon("plus-square")
                    .onClick(async () => {
                        await this.pullHighlightFromSlash();
                    });
              });
              menu.addItem((item) => {
                  item
                    .setTitle("refresh article highlights from slash")
                    .setIcon("plus-square")
                    .onClick(async () => {
                        await this.refreshArticleHighlights();
                    });
              });
          })
        );

        // add settings tab
        this.addSettingTab(new SettingTab(this.app, this));
    }

    async loadSettings() {
        this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
    }

    async saveSettings() {
        await this.saveData(this.settings);
    }

    async pullHighlightFromSlash() {
        // pull指选中highlights，然后将slash中的高亮内容拉取回ob笔记
        // 不用关系article，因为会先扫描整个笔记，获取article和highlight的关系并保存下来
        const mdView = this.app.workspace.getActiveViewOfType(MarkdownView);

        if (!mdView) return false;
        if (mdView.editor == undefined) return false;

        const selection = mdView.editor.getSelection();
        if (selection && selection.trim() !== "") {
            const [articleMap, highlightMap] = this.scanWebHighlights();
            const highlights = this.extractHighlights(selection);
            if (highlights.length <= 0) {
                console.log("no highlights in selection matched.")
                new Notice("failed: no highlights in selection matched.")
            }
            try {
                for (const highlight of highlights) {
                    const articleId = highlightMap.get(highlight.HighlightId);
                    const comments = await fetchHighlightComments(articleId, highlight.HighlightId);
                    console.log(`success: fetched article:${articleId} highlight: ${highlight.HighlightId}.`);
                    console.log(comments);
                    const parts = selection.split(/\n *> ?/);
                    let newText = parts[0] += " \n > " + comments;

                    // for (let i = 1; i < parts.length; i++) {
                    //     // 将">"后面的内容替换为Comments
                    //     newText += " \n> " + comments + (i < parts.length - 1 ? '\n>' : ''); // 如果不是最后一个部分，则在末尾添加">"
                    // }
                    mdView.editor.replaceSelection(newText);
                    new Notice(`success: updated comments: articleId: ${articleId} highlightId: ${highlight.HighlightId}`);
                    // 替换selection中的comments
                }
            } catch (error) {
                new Notice(`error: ${error}`);
                throw error;
            }
        }
    }
    async updateHighlightToSlash() {
        // push指选中highlights，然后将ob笔记中的高亮内容推送至slash
        // 不用关系article，因为会先扫描整个笔记，获取article和highlight的关系并保存下来
        const mdView = this.app.workspace.getActiveViewOfType(MarkdownView);

        if (!mdView) return false;
        if (mdView.editor == undefined) return false;

        const selection = mdView.editor.getSelection();
        try {
            if (selection && selection.trim() !== "") {
                const [articleMap, highlightMap] = this.scanWebHighlights();
                const highlights = this.extractHighlights(selection);
                if (highlights.length <= 0) {
                    console.log("no highlights in selection matched.")
                    new Notice("failed: no highlights in selection matched.")
                }
                for (const highlight of highlights) {
                    const articleId = highlightMap.get(highlight.HighlightId);
                    await updateHighlightComments(articleId, highlight.HighlightId, highlight.Comments);
                    console.log(`success: updated article:${articleId} highlight: ${highlight.HighlightId}.`);
                    new Notice(`success: updated article: ${articleId} highlight: ${highlight.HighlightId}.`);
                }
            }
        } catch (error) {
            new Notice(`error: ${error}`);
            throw error;
        }
    }
    async refreshArticleHighlights() {
        // fetch则指将整个article所有内容一起拉下来，因此必须选中一个article
        const mdView = this.app.workspace.getActiveViewOfType(MarkdownView);

        if (!mdView) return false;
        if (mdView.editor == undefined) return false;

        const selection = mdView.editor.getSelection();
        try {
            if (selection && selection.trim() !== "") {
                const articles = this.extractArticles(selection);
                if (articles.length !== 1) {
                    new Notice(`failed: please select only 1 article link.`);
                } else {
                    const articleId = articles[0][1].replace("#", "");
                    const highlightsAndComments = await fetchHighlights(articleId);
                    const newText = articles[0][0] + "\n" + highlightsAndComments;
                    // const newText = selection + "\n" + highlightsAndComments;
                    mdView.editor.replaceSelection(newText);
                    new Notice(`success: fetched highlights: articleId: ${articleId}`);
                }
            }
        }
        catch (error) {
            new Notice(`error: ${error}`);
            throw error;
        }
    }
    scanWebHighlights() : [Map<string, Map<string, string>>, Map<string, string>] {
        const mdView = this.app.workspace.getActiveViewOfType(MarkdownView);

        if (!mdView) return null;
        if (mdView.editor == undefined) return null;
        const text = mdView.data;
        const articleLinkFullMatches = this.extractArticles(text);
        const pairList = this.createPairList(articleLinkFullMatches);
        // map结构 articleId -> highlightId -> highlightComments
        let articleMap: Map<string, Map<string, string>> = new Map();
        // 反向map结构 highlightId -> articleId
        let highlightMap: Map<string, string> = new Map();
        for (const pair of pairList) {
            const articleId = pair[0][1].replace("#", "");
            const startLineNum = this.findLineNum(pair[0][0], mdView.editor);
            let endLineNum = mdView.editor.lineCount();
            if (pair[1]) {
                endLineNum = this.findLineNum(pair[1][0], mdView.editor);
            }
            // 获取了两篇内链文章的起止行号
            console.log(startLineNum);
            console.log(endLineNum);
            const content = mdView.editor.getRange({line: startLineNum, ch: 0}, {line: endLineNum, ch: 0});
            const highlights = this.extractHighlights(content);
            // 组织数据map结构 article -> highlightId
            let articleHighlightMap : Map<string, string> = new Map(); //highlightId -> highlightComments
            for (const highlight of highlights) {
                articleHighlightMap.set(highlight.HighlightId, highlight.Comments);
                highlightMap.set(highlight.HighlightId, articleId);
                //await updateShortcutViewstate(articleId, highlight.HighlightId, highlight.Comments);
            }
            articleMap.set(articleId, articleHighlightMap);
            // console.log(articleId);
            // console.log(highlights);
            // const result = await getShortcutByName(articleId);
            // console.log(result);
        }
        console.log(articleMap);
        return [articleMap, highlightMap];
    }

    extractArticles(content: string) {
        // JM：找到内链地址所在行
        // let regex = /\[@.+\]\((\#[a-f0-9]{40})\)/g;
        let regex = /\[.+\]\((\#[a-f0-9]{40})\)/g;

        let matches;
        let articleLinkFullMatches = [];
        while ((matches = regex.exec(content)) !== null) {
            articleLinkFullMatches.push([
                matches[0], // 完整的匹配项
                matches[1], // 第一个捕获组
            ]);
        }
        return articleLinkFullMatches;
    }

    extractHighlights(content: string) {
        // let regex = /\[@\]\((\#[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})\)/g; // 这个正则表达式匹配全部highlights
        // let regex = /\[@\]\((\#[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})\).*\n *>((.|\n)*?)\n(?! ?>)/g; // 这个正则表达式仅匹配具备批注评论的highlights
        let regex = /\[@\]\((\#[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})\).*\n? *(>((.|\n)*?)(\n|$)(?! ?>))?/g; // 这个可以匹配没有comments的highlights
        let matches;
        let highlightLinkFullMatches = [];
        while ((matches = regex.exec(content)) !== null) {
            highlightLinkFullMatches.push([
                matches[0], // 完整的匹配项
                matches[1], // highlightId
                matches[2], // highlight批注备注
            ]);
        }

        let highlights = [];
        for (const group of highlightLinkFullMatches) {
            const highlightFullMatch = group[0];
            const highlightId = group[1].replace("#", "");
            const comments = group[2];
            highlights.push({
                FullMatch: highlightFullMatch,
                HighlightId: highlightId,
                Comments: comments,
            })
        }
        return highlights;
    }
    createPairList(list: Array<any>) {
        let pairList = [];
        for (let i = 0; i < list.length; i++) {
            if (i % 2 === 0) { // 偶数索引，即单数个元素
                pairList.push([list[i], list[i + 1]]);
            } else if (i === list.length - 1) { // 最后一个元素，没有配对，和null配对
                pairList.push([list[i], null]);
            }
        }
        return pairList;
    }
    findLineNum(text: string, doc: Editor) {
        for (let i = 0; i < doc.lineCount(); i++) {
            let theLine = doc.getLine(i);
            if (theLine.indexOf(text.trim()) !== -1) {
                console.log(`${text}: line num: ${i}`);
                return i;
            }
        }
    }
}


class SettingTab extends PluginSettingTab {
    plugin: WebHighlighterLinkPlugin;

    constructor(app: App, plugin: WebHighlighterLinkPlugin) {
        super(app, plugin);
        this.plugin = plugin;
    }

    display(): void {
        const {containerEl} = this;
        containerEl.empty();

        // new Setting(containerEl)
        //     .setName('Origin Link Text')
        //     .setDesc('Origin Link Text.')
        //     .addText(text => text
        //         .setPlaceholder('原文地址')
        //         .setValue(this.plugin.settings.originLinkText)
        //         .onChange(async (value) => {
        //                 this.plugin.settings.originLinkText = value;
        //                 await this.plugin.saveSettings();
        //             }
        //         ));
        new Setting(containerEl)
            .setName('New Link Text')
            .setDesc('New Link Text.')
            .addText(text => text
                .setPlaceholder('在网页显示高亮')
                .setValue(this.plugin.settings.newLinkText)
                .onChange(async (value) => {
                        this.plugin.settings.newLinkText = value;
                        await this.plugin.saveSettings();
                    }
                ));
        new Setting(containerEl)
            .setName('Highlight Bullet')
            .setDesc('Highlight Bullet.')
            .addText(text => text
                .setPlaceholder('▲')
                .setValue(this.plugin.settings.highlightBullet)
                .onChange(async (value) => {
                        this.plugin.settings.highlightBullet = value;
                        await this.plugin.saveSettings();
                    }
                ));
        new Setting(containerEl)
            .setName('Toggle Regenerate From Detail')
            .setDesc('Toggle Regenerate From Detail.')
            .addToggle(toggle => toggle
                .setValue(this.plugin.settings.toggleRegenerateFromDetail)
                .onChange(async (value) => {
                        this.plugin.settings.toggleRegenerateFromDetail = value;
                        await this.plugin.saveSettings();
                    }
                ));
    }
}
